/*#include <sys/types.h>*/
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>

#include <stdlib.h>
#include <string.h>
#include <getopt.h>
#include <errno.h>

#include "tellenc.h"

#include "my_debug.h"

struct tellenc_opts {
	int				teo_help;
	int				teo_verbose;
	char			*teo_file;
};

static int			get_cmdline_opts(int argc, char *_argv[],
									 struct tellenc_opts *_opts);
static int			check_cmdline_opts(struct tellenc_opts *_opts);
static int			usage(const char *_cmd);

static int
usage(const char *cmd)
{
	LOGINFO_R("USAGE\n"
			  "  %s [OPTIONS] FILE\n", cmd);
	LOGINFO_R("OPTIONS\n"
			  "  -h -?         This help screen\n"
			  "  -f FILE       Specify text file\n"
			  "  -v            Enable verbose mode\n"
			  "Copyright (c) 2010, 2011, Wu Yongwei (wyw.dcweb.cn), "
			  "zeroxia (zerox.me)\n"
			  "All rights reserved.\n"
	);

	return 0;
}

static int
get_cmdline_opts(int argc, char *argv[], struct tellenc_opts *opts)
{
	static const char *optstr = "f:vh?";

	int c, is_help = 0;

	memset(opts, 0, sizeof(*opts));

	while ((c = getopt(argc, argv, optstr)) != -1) {
		switch (c) {
		case 'f':
			opts->teo_file = optarg;
			break;

		case 'v':
			opts->teo_verbose = 1;
			break;

		case 'h':
		case '?':
			is_help = 1;
			/* FALL THROUGH */
		default:
			if (!is_help) {
				LOGERROR("%s unknown option: %c\n", __func__, c);
			}
			opts->teo_help = 1;
			return 1; /* 1: for help */
		}
	}

	if (optind < argc) {
		if (opts->teo_file != NULL) {
			LOGDEBUG_LV(1, "%s repeated text file option\n", __func__);
		}
		opts->teo_file = argv[optind];
	}

	return 0;
}

static int
check_cmdline_opts(struct tellenc_opts *opts)
{
	if (opts->teo_file == NULL) {
		LOGERROR("%s no text file specified\n", __func__);
		return -1;
	}

	if (opts->teo_verbose) {
		LOGDEBUG_LV(1, "%s verbose mode is on\n", __func__);
	}

	return 0;
}

static int
test_tellenc(const struct tellenc_opts *opts)
{
#define TEST_TELLENC_FILE_SIZE_MAX	(1024 * 200)
	enum tellenc_enc enc;
	struct stat sb;
	char *buf;
	int rc, fd = -1, flags = 0, bom_len = 0;
	int buflen, nread;

	rc = stat(opts->teo_file, &sb);
	if (rc == -1) {
		LOGERROR("%s stat(\"%s\") fail: %d\n",
				__func__, opts->teo_file, errno);
		return -1;
	}

	if (sb.st_size > TEST_TELLENC_FILE_SIZE_MAX) {
		LOGERROR("%s file \"%s\" size %lld, too large (allowd max %d)\n",
				 __func__, opts->teo_file, sb.st_size,
				 TEST_TELLENC_FILE_SIZE_MAX);
		return -1;
	}

	buflen = (int)sb.st_size;
	buf = malloc(buflen);
	if (buf == NULL) {
		LOGERROR("%s malloc(%d) for file buf failed\n", __func__, buflen);
		return -1;
	}

	fd = open(opts->teo_file, O_RDONLY);
	if (fd == -1) {
		LOGERROR("%s open \"%s\" failed: %d\n", __func__,
				 opts->teo_file, errno);
		goto back;
	}

	nread = 0;
	while (nread < buflen) {
		rc = read(fd, buf, buflen - nread);
		if (rc < 0) {
			LOGERROR("%s read(%d, buf, %d) fail: %d\n",
					__func__, fd, buflen - nread, errno);
			goto back;
		} else if (rc == 0) {
			break;
		}
		nread += rc;
	}

	if (opts->teo_verbose) {
		LOGDEBUG_LV(1, "%s \"%s\": read %d bytes\n",
					__func__, opts->teo_file, buflen);
		flags |= TELLENC_FLAG_VERBOSE;
	}

	enc = tellenc_tell(buf, buflen, &bom_len, flags);

	if (opts->teo_verbose) {
		LOGINFO("%s file \"%s\", encoding: %s, BOM len %d\n", __func__,
				opts->teo_file, tellenc_enc_name(enc), bom_len);
	} else {
		LOGINFO_R("%s\n", tellenc_enc_name(enc));
	}

back:
	if (buf != NULL)
		free(buf);
	if (fd >= 0)
		close(fd);
	return rc;
}

int
main(int argc, char *argv[])
{
	struct tellenc_opts the_opts;
	int rc;

	rc = get_cmdline_opts(argc, argv, &the_opts);
	if (rc < 0) {
		return -1;
	} else if (rc > 0) {
		return usage(argv[0]);
	}

	rc = check_cmdline_opts(&the_opts);
	if (rc != 0) {
		usage(argv[0]);
		return -1;
	}

	rc = test_tellenc(&the_opts);

	return rc;
}
